﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using Lidgren.Network;
using Model.LiveControl;
using Network;
using Network.Messages.LiveControl;
using Network.Messages.LiveControl.C2S;
using Network.Messages.LiveControl.S2C;

namespace Providers.LiveControl.Client
{
    public class LiveControlProvider : Provider
    {
        private readonly int _framIgnore;
        private readonly Dictionary<uint, Screenshot> _pendingScreenshots;

        private int _currentProcPtr = -1;

        public bool FlagFirstFrame { get; set; } = true;
        private bool _flagTick;

        public bool FlagNeedNewScreen;

        public LiveControlProvider(NetworkPeer network)
            : base(network)
        {
            _pendingScreenshots = new Dictionary<uint, Screenshot>(1000);
            _framIgnore = 10;
        }

        private int _currentScreenId =0;
        public int CurrentScreenId
        {
            get
            {
                return _currentScreenId;
            }

            set
            {
                if (_currentScreenId ==value)
                {
                    return;
                }
                ResetScreenIndex(value);
            }
        }

        public void ResetScreenIndex(int value)
        {
            RequsetScreenRectMessage tMessage = new RequsetScreenRectMessage()
            {
                ScreenIndex = value,
            };
            Network.SendMessage(tMessage,
                NetDeliveryMethod.ReliableOrdered,
                3);

            CurrentProcPtr = -1;
            ChangeProcPtr(-1);
            _currentScreenId = value;

        }

        public bool FlagShowFullScreen => _currentProcPtr <= 0;

      
        
        public int CurrentProcPtr
        {
            get { return _currentProcPtr; }
            set
            {
                if (_currentProcPtr == value)
                {
                    return;
                }


                ChangeProcPtr(value);

            }
        }

        private void ChangeProcPtr(int value)
        {
            #region 通知服务端

            //通知服务端：
            // 如果被重新设置为-1或其它负数，
            // 也就是请求全屏，那么向服务器重新请求关键帧
            if (value <= 0)
            {
                FlagFirstFrame = true;
            }
            // 当句柄发生了变化，清除之前的渲染
            if (_currentProcPtr > 0)
            {
                Network.SendMessage(new RequestClearRectMessage {PtrNeedClear = _currentProcPtr},
                    NetDeliveryMethod.ReliableOrdered,
                    3);
            }

            #endregion

            _currentProcPtr = value;

            #region 通知客户端

            //通知客户端：通知状态发生了改变
            OnPickedStatusChanged?.Invoke(null, new WindowPickedStatus
            {
                FlagFullScreen = FlagShowFullScreen,
                Ptr = value
            });
            #endregion

        }


        /// <summary>
        ///     按帧获取，等时间间隔请求屏幕，可以解决丢包导致不连续显示的问题
        /// </summary>
        /// <param name="now">程序启动时间</param>
        /// <param name="frameCounter">帧计数</param>
        public override void Heartbeat(float now, uint frameCounter)
        {
            if (frameCounter%_framIgnore != 0 || !_flagTick)
            {
                return;
            }

            Network.SendMessage(new RequestScreenshotMessage {FlagFirstFrame = FlagFirstFrame, Id = CurrentProcPtr,ScreenIndex = CurrentScreenId});
            FlagFirstFrame = false;
        }

        public void StartTick()
        {
            FlagFirstFrame = true;
            _flagTick = true;
        }

        public void StopTick()
        {
            FlagFirstFrame = true;
            _flagTick = false;
        }

        public override void RegisterMessageHandlers()
        {
            Network.RegisterMessageHandler<ResponseBeginScreenshotMessage>(OnResponseBeginScreenshotMessageReceived);
            Network.RegisterMessageHandler<ResponseScreenshotMessage>(OnResponseScreenshotMessageReceived);
            Network.RegisterMessageHandler<ResponseEndScreenshotMessage>(OnResponseEndScreenshotMessageReceived);
            Network.RegisterMessageHandler<ResponseEmptyScreenshotMessage>(OnResponseEmptyScreenshotMessageReceived);
            Network.RegisterMessageHandler<ResponseTime>(OnResponseTime);

            Network.RegisterMessageHandler<ResponseProccessListMessage>(OnProcessListMessageReceived);
            Network.RegisterMessageHandler<ResponseRectListMessage>(OnRectListMessage);

            Network.RegisterMessageHandler<ResponseRectChangeMessage>(OnRectChangeMessageReceived);
            Network.RegisterMessageHandler<ResponseCurrentProcPtr>(OnWindowPickedReceived);

            Network.RegisterMessageHandler<ServerStatusMessage>(OnServerStatusMessageReceived);
            Network.RegisterMessageHandler<ResponseScreenRectMessage>(OnResponseScreenRectMessageReceived);

            Network.RegisterMessageHandler<CursorMessage>(OnCursorMessageHandler);

            Network.RegisterMessageHandler<KnowladgeServerMachineShutDown>(OnServermachineShutdown);

            Network.RegisterMessageHandler<ResponseFullScreenshotMessage>(OnFullScreenshotMessageReceived);

            Network.RegisterMessageHandler<S2CResponseShareFormListMessage>(RecivedFormListMessage);
            Network.RegisterMessageHandler<S2CTellClientFormItemUpdate>(ReceivedFormItemUpdate);
            Network.RegisterMessageHandler<S2CTellClientFormMinisizedMessage>(ReceivedFormMinisized);
            Network.RegisterMessageHandler<S2CTellClientFormClosedMessage>(ReceivedFormClosed);
            Network.RegisterMessageHandler<S2CTellClientYouGetTheControl>(ReceivedGetControl);
            Network.RegisterMessageHandler<S2CTellClientYourControlBeRecoveredMessage>(ReceivedLoseControl);
            Network.RegisterMessageHandler<S2CRefuseControlMessage>(ReceivedRefuseMessage);
            Network.RegisterMessageHandler<S2CRefuseControlApplyMessage>(ReceivedRefuseControlApplyMessage);
            Network.RegisterMessageHandler<S2CRequestRecoverControlMessage>(ReceivedRecoverMessage);
        }

        private void ReceivedRecoverMessage(MessageEventArgs<S2CRequestRecoverControlMessage> obj)
        {
            OnReceivedRequestReCoverControlMessge?.Invoke(this,obj.Message);
        }

        private void ReceivedRefuseControlApplyMessage(MessageEventArgs<S2CRefuseControlApplyMessage> obj)
        {
            OnReceivedRefuseControlApplyMessage?.Invoke(this,obj.Message);
        }

        /// <summary>
        /// 点击操作被拒绝
        /// </summary>
        /// <param name="obj"></param>
        private void ReceivedRefuseMessage(MessageEventArgs<S2CRefuseControlMessage> obj)
        {
            Log.C.LogtoTextDebug(modelName, "ReceivedRefuseMessage", "控制操作被拒绝");
            OnReceivedRefuseControlMessage?.Invoke(this,obj.Message);
        }

        private string modelName = "LiveControlProvider";
        private void ReceivedLoseControl(MessageEventArgs<S2CTellClientYourControlBeRecoveredMessage> obj)
        {
            Log.C.LogtoTextDebug(modelName, "ReceivedLoseControl", "失去控制权");
            OnReceivedLoseControl?.Invoke(this,obj.Message);
        }

        private void ReceivedGetControl(MessageEventArgs<S2CTellClientYouGetTheControl> obj)
        {
            Log.C.LogtoTextDebug(modelName, "ReceivedGetControl", "获得控制权");
            OnReceivedGetControl?.Invoke(this,obj.Message);
        }

        private void ReceivedFormClosed(MessageEventArgs<S2CTellClientFormClosedMessage> obj)
        {
            Log.C.LogtoTextDebug(modelName, "ReceivedFormClosed", "共享窗口被关闭");
            OnReceivedFormClosed?.Invoke(this,obj.Message);
        }

        private void ReceivedFormMinisized(MessageEventArgs<S2CTellClientFormMinisizedMessage> obj)
        {
            Log.C.LogtoTextDebug(modelName, "ReceivedFormMinisized", "共享窗口被最小化");
            OnReceivedFormMinisized?.Invoke(this,obj.Message);
        }

        private void ReceivedFormItemUpdate(MessageEventArgs<S2CTellClientFormItemUpdate> obj)
        {
            Log.C.LogtoTextDebug(modelName, "ReceivedFormItemUpdate", "共享窗口状态更新");
            OnFormItemUpdate?.Invoke(this, obj.Message);
        }

        private void RecivedFormListMessage(MessageEventArgs<S2CResponseShareFormListMessage> obj)
        {
            Log.C.LogtoTextDebug(modelName, "RecivedFormListMessage", "获取可共享的窗口列表");
            OnFormListReceived?.Invoke(this, obj.Message);
        }


        private void OnFullScreenshotMessageReceived(MessageEventArgs<ResponseFullScreenshotMessage> obj)
        {

            if (!obj.Message.ReadComplete)
            {
                //导致读取没有完成的原因可能是内存不够
                return;
            }
            Screenshot tScreenshot = new Screenshot(obj.Message.Image, obj.Message.Region, obj.Message.Number,obj.Message.SendFrameIndex);
            OnScreenshotReceived?.Invoke(this,
           new ScreenshotMessageEventArgs { Screenshot = tScreenshot });

        }

        private void OnServermachineShutdown(MessageEventArgs<KnowladgeServerMachineShutDown> obj)
        {
            OnServerShutdown?.Invoke(this,obj.Message);
        }

        private void OnCursorMessageHandler(MessageEventArgs<CursorMessage> messageEventArgs)
        {
            OnCursorMessageEvent?.Invoke(this, messageEventArgs.Message);
        }

        private void OnResponseScreenRectMessageReceived(MessageEventArgs<ResponseScreenRectMessage> obj)
        {
            OnResponseScreenRectReceived?.Invoke(this, obj.Message);
        }

        private void OnServerStatusMessageReceived(MessageEventArgs<ServerStatusMessage> obj)
        {
            OnSeverStatusReceived?.Invoke(this, obj.Message);
        }

        private void OnResponseTime(MessageEventArgs<ResponseTime> obj)
        {
            var now = DateTime.Now.Ticks;
            var tDif = new TimeSpan(now - obj.Message.StartTime);
            if (tDif.Seconds > 0.3)
            {
                Trace.WriteLine("Received OnResponseTime.");
                Trace.WriteLine(tDif.TotalSeconds + "seconds");
            }
        }

        private int currentIndex = -1;
        private void OnResponseBeginScreenshotMessageReceived(MessageEventArgs<ResponseBeginScreenshotMessage> e)
        {
            //Trace.WriteLine("Received ResponseBeginScreenshotMessage.");
            _pendingScreenshots.Add(e.Message.Number,
                new Screenshot(new byte[e.Message.FinalLength], e.Message.Region, e.Message.Number, currentIndex++));
        }

        private void OnResponseScreenshotMessageReceived(MessageEventArgs<ResponseScreenshotMessage> e)
        {
            //Trace.WriteLine(
            //    $"Received ResponseScreenshotMessage, Number: {e.Message.Number}, Size: {GetKbFromBytes(e.Message.Image.Length)} KB");
            var num = e.Message.Number;
            try
            {
                // Slowly build our image bytes
                Buffer.BlockCopy(e.Message.Image, 0, _pendingScreenshots[num].Image,
                    e.Message.SendIndex * Server.LiveControlProvider.Mtu, e.Message.Image.Length);
            }
            catch (Exception)
            {
                
                //throw;
            }

        }

        private void OnResponseEndScreenshotMessageReceived(MessageEventArgs<ResponseEndScreenshotMessage> e)
        {
            //Trace.WriteLine("Received ResponseEndScreenshotMessage.");
            try
            {
                OnScreenshotReceived?.Invoke(this,
               new ScreenshotMessageEventArgs { Screenshot = _pendingScreenshots[e.Message.Number] });
                _pendingScreenshots.Remove(e.Message.Number);
            }
            catch (Exception)
            {
                
                //throw;
            }
           
        }

        /// <summary>
        ///     Raises the <see cref="E:ResponseEmptyScreenshotMessageReceived" /> event.
        /// </summary>
        /// <param name="e">The <see cref="ResponseEmptyScreenshotMessage" /> instance containing the event data.</param>
        private void OnResponseEmptyScreenshotMessageReceived(MessageEventArgs<ResponseEmptyScreenshotMessage> e)
        {
            FlagNeedNewScreen = true;
        }


        private static float GetKbFromBytes(long bytes)
        {
            return bytes/(float) 1024;
        }

        public void RequestScreenshot()
        {
            Network.SendMessage(new RequestScreenshotMessage {Id = CurrentProcPtr});
        }

        public event EventHandler<ScreenshotMessageEventArgs> OnScreenshotReceived;
        public event EventHandler<RectChangeMessageEventArgs> OnRectChangeReceived;
        public event EventHandler<ProcessesResponeMessageEventArgs> OnProcessesReceived;
        public event EventHandler<RectListResponeMessageEventArgs> OnRectesMessage;
        public event EventHandler<WindowPickedEventArgs> OnWindowPickedevent;
        public event EventHandler<WindowPickedStatus> OnPickedStatusChanged;
        public event EventHandler<ServerStatusMessage> OnSeverStatusReceived;
        public event EventHandler<ResponseScreenRectMessage> OnResponseScreenRectReceived;
        public event EventHandler<CursorMessage> OnCursorMessageEvent;
        public event EventHandler<KnowladgeServerMachineShutDown> OnServerShutdown;

        public event EventHandler<S2CResponseShareFormListMessage> OnFormListReceived;
        public event EventHandler<S2CTellClientFormItemUpdate> OnFormItemUpdate ;
        public event EventHandler<S2CTellClientFormMinisizedMessage> OnReceivedFormMinisized;
        public event EventHandler<S2CTellClientFormClosedMessage> OnReceivedFormClosed;
        public event EventHandler<S2CTellClientYouGetTheControl> OnReceivedGetControl;
        public event EventHandler<S2CTellClientYourControlBeRecoveredMessage> OnReceivedLoseControl;
        public event EventHandler<S2CRefuseControlMessage> OnReceivedRefuseControlMessage;
        public event EventHandler<S2CRefuseControlApplyMessage> OnReceivedRefuseControlApplyMessage;
        public event EventHandler<S2CRequestRecoverControlMessage> OnReceivedRequestReCoverControlMessge; 
        #region 单窗口相关代码

        public void RequestProcList()
        {
            Network.SendMessage(new RequestProccessListMessage(), NetDeliveryMethod.ReliableOrdered,
                3);
        }

        private void OnRectChangeMessageReceived(MessageEventArgs<ResponseRectChangeMessage> obj)
        {
            OnRectChangeReceived?.Invoke(null, new RectChangeMessageEventArgs {Rect = obj.Message.Rect});
        }

        private void OnProcessListMessageReceived(MessageEventArgs<ResponseProccessListMessage> obj)
        {
            OnProcessesReceived?.Invoke(null,
                new ProcessesResponeMessageEventArgs {ProcessInfoList = obj.Message.ProcList});
        }

        private void OnRectListMessage(MessageEventArgs<ResponseRectListMessage> obj)
        {
            OnRectesMessage?.Invoke(null, new RectListResponeMessageEventArgs {RectList = obj.Message.RectList});
        }

        private void OnWindowPickedReceived(MessageEventArgs<ResponseCurrentProcPtr> obj)
        {
            OnWindowPickedevent?.Invoke(null,
                new WindowPickedEventArgs {Rect = obj.Message.Rect, Name = obj.Message.ProcName});

            CurrentProcPtr = obj.Message.Rect.Ptr;
        }

        #endregion

        #region 鼠标事件

        public void NotifyGetWindow(CoustomMouseEventArgs coustomMouseEventArgs)
        {
            Network.SendEventMessage(new GetWindowFormPointMessage {MouseEventArgs = coustomMouseEventArgs,ScreenIndex = _currentScreenId});
        }

        public void NotifyMouseClick(CoustomMouseEventArgs mouseEventArgs)
        {
            Network.SendEventMessage(new MouseClickMessage {MouseEventArgs = mouseEventArgs, ScreenIndex = _currentScreenId });
        }

        public void NotifyMouseMove(CoustomMouseEventArgs mouseEventArgs)
        {
            Network.SendEventMessage(new MouseMoveMessage {MouseEventArgs = mouseEventArgs, Now = DateTime.Now.Ticks, ScreenIndex = _currentScreenId });
        }

        public void NotifyMouseDoubleClick(CoustomMouseEventArgs mouseEventArgs)
        {
            Network.SendEventMessage(new MouseDoubleClickMessage {MouseEventArgs = mouseEventArgs, ScreenIndex = _currentScreenId });
        }

        public void NotifyMouseDown(CoustomMouseEventArgs coustomMouseEventArgs)
        {
            Network.SendEventMessage(new MouseDownMessage {MouseEventArgs = coustomMouseEventArgs, ScreenIndex = _currentScreenId });
        }

        public void NotifyMouseUp(CoustomMouseEventArgs coustomMouseEventArgs)
        {
            Network.SendEventMessage(new MouseUpMessage {MouseEventArgs = coustomMouseEventArgs, ScreenIndex = _currentScreenId });
        }

        public void NotifyMouseWheel(CoustomMouseEventArgs coustomMouseEventArgs)
        {
            Network.SendEventMessage(new MouseScrollMessage {MouseEventArgs = coustomMouseEventArgs, ScreenIndex = _currentScreenId });
        }

        #endregion

        #region 键盘事件

        public void NotifyKeyDown(KeyDownMessage keyEventArgs)
        {
            Network.SendEventMessage(keyEventArgs);
        }

        public void NotifyKeyPress(KeyPressMessage keyPressEventArgs)
        {
            Network.SendEventMessage(keyPressEventArgs);
        }

        public void NotifyKeyUp(KeyUpMessage keyEventArgs)
        {
            Network.SendEventMessage(keyEventArgs);
        }

        #endregion

        public void ConnectForm(FormItemModel model)
        {
            C2SConnectFormMessage tMessage = new C2SConnectFormMessage {FormItemModel = model};
            Network.SendMessage(tMessage);
        }

        public void RequstFormList()
        {
            C2SRequestShareFormListMessage tMessage = new C2SRequestShareFormListMessage();
            Network.SendMessage(tMessage);
        }

        public void RequsetControlByForce()
        {
            C2SRequestControlForceMessge tMessge = new C2SRequestControlForceMessge();
            Network.SendMessage(tMessge);
        }

        public void RequestControlByApply()
        {
            C2SRequestControlMessge tMessge = new C2SRequestControlMessge();
            Network.SendMessage(tMessge);
        }

        public void SendResultMessage(C2SResponseControlResultMessge tMessage)
        {
            Network.SendMessage(tMessage);
        }

        public void ReshowShareForm(FormItemModel formItemModel)
        {
            var tMessage = new C2SReshowMinisizeFormMessage {FormItemModel = formItemModel};
            Network.SendMessage(tMessage);}

        public void SendChangeWindowMessage(C2SChangeWindowStatusMessage tMessage)
        {
            Network.SendMessage(tMessage);
        }
    }
}